﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Demo.SharePoint.Utilities;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.SharePoint.WebPartPages;
using WebPart = System.Web.UI.WebControls.WebParts.WebPart;
using SPWebPart = Microsoft.SharePoint.WebPartPages.WebPart;

namespace Demo.SharePoint.WebParts.OfficeLocator
{
    [ToolboxItemAttribute(false)]
    [Guid("7d23c3fb-3bd7-4fa1-9653-c5a11b7b3a55")]
    [XmlRoot(Namespace = "http://schemas.sorethumbmedia.com/sharepoint")]
    public class OfficeLocatorPart : SPWebPart
    {
        #region Members
        private HiddenField hidQuery;
        private HiddenField hidOfficeId;
        private Button btnHiddenSubmit;
        private Label lblMsg;
        private Panel pnlResults;
        private Repeater rptResults;
        private Panel pnlMap;
        private HtmlGenericControl divMap;
        private bool mapLoaded;
        #endregion

        private void DisplayOffices()
        {
            EnsureChildControls();

            mapLoaded = true;

            // Get selected office id
            int selOfficeId;
            int.TryParse(hidOfficeId.Value, out selOfficeId);

            // Get the list of offices that were presented to the user
            SPListItemCollection offices = OfficeSearch.Search(hidQuery.Value, 10, OfficeListUrl);
            if (offices == null || offices.Count == 0)
            {
                pnlMap.Visible = pnlResults.Visible = false;
                lblMsg.Text = "No offices were found matching your criteria.";
                lblMsg.ForeColor = Color.Red;
                return;
            }

            StringBuilder js = new StringBuilder(@"
function STM_loadGoogleMap() 
{
	var map = new GMap2(document.getElementById('" + divMap.ClientID + @"'));
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    var bounds = new GLatLngBounds();
	var icon1 = new GIcon();
    icon1.image = ""_layouts/images/Demo.SharePoint.WebParts/Markers/marker1.png"";
    icon1.shadow = ""_layouts/images/Demo.SharePoint.WebParts/Markers/markerShadow.png"";
    icon1.iconSize = new GSize(20, 34);
    icon1.shadowSize = new GSize(37, 34);
    icon1.iconAnchor = new GPoint(9, 34);
    icon1.infoWindowAnchor = new GPoint(9, 2);
");

            // New list for re-ordered offices
            List<SPItem> orderedOffices = new List<SPItem>(offices.Count);

            // Make marker 1 the office the user selected
            int index = 1;
            SPListItem selectedItem = null;
            try
            {
                selectedItem = offices.GetItemById(selOfficeId);
            }
            catch (ArgumentException)
            { }
            if (selectedItem != null)
            {
                AddGoogleMarker(js, index, Convert.ToString(selectedItem["Latitude"]), Convert.ToString(selectedItem["Longitude"]));
                orderedOffices.Add(selectedItem);
                index++;
            }

            foreach (SPListItem item in offices)
            {
                if (item.ID == selOfficeId)
                    continue;

                if (index > 1)
                    js.Append(@"
	var icon" + index + @" = new GIcon(icon1);
	icon" + index + @".image = ""_layouts/images/Demo.SharePoint.WebParts/Markers/marker" + index + @".png"";
");

                AddGoogleMarker(js, index, Convert.ToString(item["Latitude"]), Convert.ToString(item["Longitude"]));
                orderedOffices.Add(item);
                index++;
            }

            js.Append("map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));\r\n");
            // addOverlay needs to be called after setCenter
            for (index = 1; index <= offices.Count; index++)
                js.Append(String.Format("map.addOverlay(marker{0});\r\n", index));

            js.Append(@"
}

if (window.addEventListener) window.addEventListener('load', STM_loadGoogleMap, true);
if (window.attachEvent) window.attachEvent('onload', STM_loadGoogleMap);
");

            Page.ClientScript.RegisterStartupScript(GetType(), "STMGoogle", js.ToString(), true);

            if (!Page.ClientScript.IsClientScriptIncludeRegistered(GetType(), "GoogleMapInc"))
            {
                string googleMapsURL = "http://maps.google.com/maps?file=api&v=2&key=" + GoogleMaps.GetApiKey(SPContext.Current.Web);
                Page.ClientScript.RegisterClientScriptInclude(GetType(), "GoogleMapInc", googleMapsURL);
            }

            pnlMap.Visible = pnlResults.Visible = true;

            SetupRepeater();
            rptResults.DataSource = orderedOffices;
            rptResults.DataBind();
        }

        private static void AddGoogleMarker(StringBuilder js, int index, string latitude, string longitude)
        {
            js.Append(String.Format("var marker{0} = new GMarker(new GLatLng({1}, {2}), icon{3});\r\n", index, latitude, longitude, index));
            js.Append(String.Format("bounds.extend(marker{0}.getPoint());\r\n", index));
            js.Append("GEvent.addListener(marker" + index + ", 'click', function() { STM_locationResultDetailedHeadingOnClick(" + (index - 1) + "); } ); ");
        }

        private void SetupRepeater()
        {
            rptResults.HeaderTemplate = new OfficeResultsTemplate(ListItemType.Header);
            rptResults.ItemTemplate = new OfficeResultsTemplate(ListItemType.Item);
            rptResults.AlternatingItemTemplate = new OfficeResultsTemplate(ListItemType.AlternatingItem);
            rptResults.FooterTemplate = new OfficeResultsTemplate(ListItemType.Footer);
        }

        private static void RenderSearchBar(HtmlTextWriter writer)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "stm-searchBar");
            writer.RenderBeginTag(HtmlTextWriterTag.Hr);
            writer.RenderEndTag(); // Hr

            writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");
            writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
            writer.AddAttribute(HtmlTextWriterAttribute.Border, "0");
            writer.RenderBeginTag(HtmlTextWriterTag.Table);
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "stm-searchBar");
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write("Search Locations:&nbsp;");
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
            writer.AddAttribute(HtmlTextWriterAttribute.Id, "stmLocation");
            writer.AddAttribute(HtmlTextWriterAttribute.AutoComplete, "off");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "Enter City or Zip");
            writer.AddAttribute("onkeyup", "STM_locationChanged()");
            writer.AddAttribute("onfocus", "STM_locationFocus();STM_locationChanged();this.hasFocus=true");
            writer.AddAttribute("onblur", "STM_locationBlur();this.hasFocus=false");
            writer.AddAttribute("onclick", "STM_locationChanged()");
            writer.RenderBeginTag(HtmlTextWriterTag.Input);
            writer.RenderEndTag(); // Input
            writer.RenderEndTag(); // Td

            writer.AddAttribute(HtmlTextWriterAttribute.Class, "stm-searchBar");
            writer.AddStyleAttribute(HtmlTextWriterStyle.PaddingLeft, "10px");
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
            writer.AddAttribute("onclick", "STM_ClearResults()");
            writer.RenderBeginTag(HtmlTextWriterTag.Button);
            writer.Write("Clear Results");
            writer.RenderEndTag(); // Button
            writer.RenderEndTag(); // Td

            writer.RenderEndTag(); // Tr
            writer.RenderEndTag(); // Table

            writer.AddAttribute(HtmlTextWriterAttribute.Class, "stm-searchBar");
            writer.RenderBeginTag(HtmlTextWriterTag.Hr);
            writer.RenderEndTag(); // Hr
            writer.RenderEndTag(); // Div

            writer.AddAttribute(HtmlTextWriterAttribute.Id, "stmLocationResults");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.RenderEndTag(); // Div
        }

        private void AddClientScript()
        {
            //if (!Page.ClientScript.IsClientScriptIncludeRegistered("STMjquery.js"))
            //    Page.ClientScript.RegisterClientScriptInclude(GetType(), "STMjquery.js", "_layouts/Demo.SharePoint.WebParts/STMjquery.js");
            if (!Page.ClientScript.IsClientScriptIncludeRegistered(GetType(), Constants.jquery))
                Page.ClientScript.RegisterClientScriptInclude(GetType(), Constants.jquery, SPUtility.GetServerRelativeUrlFromPrefixedUrl(string.Format("~sitecollection/_layouts/Demo.SharePoint.WebParts/{0}", Constants.jquery)));
            if (!Page.ClientScript.IsClientScriptIncludeRegistered(GetType(), Constants.officeLocator))
                Page.ClientScript.RegisterClientScriptInclude(GetType(), Constants.officeLocator, SPUtility.GetServerRelativeUrlFromPrefixedUrl(string.Format("~sitecollection/_layouts/Demo.SharePoint.WebParts/{0}", Constants.officeLocator)));

            #region js
            string js = @"
function STM_getLocationListUrl()
{
	return '" + OfficeListUrl + @"';
}

function STM_setSelectedLocation(locId)
{
	var hidQuery = document.getElementById('" + hidQuery.ClientID + @"');
	hidQuery.value = document.getElementById('stmLocation').value;

	var hidOfficeId = document.getElementById('" + hidOfficeId.ClientID + @"');
	hidOfficeId.value = locId;
}

function STM_ClearResults()
{
	var pnlResults = document.getElementById('" + pnlResults.ClientID + @"');
	if (pnlResults) {pnlResults.style.display = 'none';}
	var pnlMap = document.getElementById('" + pnlMap.ClientID + @"');
	if (pnlMap) {pnlMap.style.display = 'none';}
	var hidQuery = document.getElementById('" + hidQuery.ClientID + @"');
	hidQuery.value = '';
	var hidOfficeId = document.getElementById('" + hidOfficeId.ClientID + @"');
	hidOfficeId.value = '';
}

function STM_submitSelectedLocation()
{
	" + Page.ClientScript.GetPostBackEventReference(btnHiddenSubmit, string.Empty) + @"
}
";
            #endregion

            if (!Page.ClientScript.IsClientScriptBlockRegistered(GetType(), "STM"))
                Page.ClientScript.RegisterClientScriptBlock(GetType(), "STM", js, true);
        }

        #region Overrides
        protected override void CreateChildControls()
        {
            btnHiddenSubmit = new Button { ID = "btnHiddenSubmit", Width = new Unit(0), Height = new Unit(0) };
            btnHiddenSubmit.Style.Add(HtmlTextWriterStyle.Display, "none");
            lblMsg = new Label { ID = "lblMsg", EnableViewState = false };
            hidQuery = new HiddenField { ID = "hidQuery" };
            hidOfficeId = new HiddenField { ID = "hidOfficeId" };
            pnlResults = new Panel { ID = "pnlResults", Visible = false };
            rptResults = new Repeater { ID = "rptResults" };
            pnlResults.Controls.Add(rptResults);
            pnlMap = new Panel { ID = "pnlMap", Visible = false };
            divMap = new HtmlGenericControl { ID = "googleMap", TagName = "div" };
            divMap.Attributes.Add("class", "stm-googleMap");
            pnlMap.Controls.AddAt(0, divMap);

            Controls.Add(lblMsg);
            Controls.Add(pnlMap);
            Controls.Add(pnlResults);
            Controls.Add(hidQuery);
            Controls.Add(hidOfficeId);
            Controls.Add(btnHiddenSubmit);

            btnHiddenSubmit.Click += btnHiddenSubmit_Click;
            rptResults.ItemDataBound += rptResults_ItemDataBound;
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            if (string.IsNullOrEmpty(OfficeListUrl) || !OfficeListUrl.StartsWith(SPContext.Current.Site.Url))
            {
                writer.Write("The &quot;Office List URL&quot; property must be set to a valid list URL before this web part can be used.");
            }
            else
            {
                EnsureChildControls();

                RenderSearchBar(writer);
            }
            base.RenderContents(writer);
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            // Reload map on postbacks not caused by this web part
            if (!String.IsNullOrEmpty(hidQuery.Value))
            {
                if (!mapLoaded)
                    DisplayOffices();
            }
            else
                pnlMap.Visible = false;

            LiteralControl cssInclude = new LiteralControl("<link href='_layouts/Demo.SharePoint.WebParts/OfficeLocator.css' rel='stylesheet' type='text/css' />");
            Page.Header.Controls.Add(cssInclude);

            AddClientScript();
        }

        public override ToolPart[] GetToolParts()
        {

            ToolPart[] toolparts = new ToolPart[2];
            CustomPropertyToolPart custom = new CustomPropertyToolPart();
            WebPartToolPart wptp = new WebPartToolPart();
            custom.ChromeState = PartChromeState.Normal;
            custom.Expand(0);
            toolparts[0] = custom;
            toolparts[1] = wptp;

            return toolparts;
        }

        #endregion

        #region Properties

        private string officeListUrl;

        /// <summary>
        /// Gets or sets the office list URL.
        /// </summary>
        /// <value>The office list URL.</value>
        [Browsable(true)]
        [Category("Custom Settings")]
        [WebPartStorage(Storage.Shared)]
        [FriendlyName("Office List")]
        [Description("The list to search for locations from.")]
        [UrlProperty]
        public string OfficeListUrl
        {
            get
            {
                return officeListUrl;
            }
            set
            {
                if (value.StartsWith(SPUtility.SiteRelativeUrlPrefix) || value.StartsWith(SPUtility.WebRelativeUrlPrefix)) value = SPUtility.GetServerRelativeUrlFromPrefixedUrl(value);
                officeListUrl = (value.StartsWith("http://") || value.StartsWith("https://") ? value : SPUtility.GetFullUrl(SPContext.Current.Site, value));
            }
        }

        #endregion

        #region Events
        private void btnHiddenSubmit_Click(object sender, EventArgs e)
        {
            DisplayOffices();
        }

        private void rptResults_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Header)
            {
                ((Label)e.Item.FindControl("lblQuery")).Text = hidQuery.Value;
            }
            else if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {

                ((Label)e.Item.FindControl("lblIndex")).Text = (e.Item.ItemIndex + 1).ToString();
                SPListItem item = (SPListItem)e.Item.DataItem;
                ((Label)e.Item.FindControl("lblOffice")).Text = item["Title"].ToString();
                Label lblOfficeDetails = (Label)e.Item.FindControl("lblOfficeDetails");
                lblOfficeDetails.Text = Convert.ToString(item["WorkAddress"]);
                //lblOfficeDetails.Text += (String.IsNullOrEmpty(Convert.ToString(item["OtherAddressStreet"])) ? String.Empty : "<br/>" + Convert.ToString(item["OtherAddressStreet"]));
                lblOfficeDetails.Text += "<br/>" + Convert.ToString(item["WorkCity"]);
                lblOfficeDetails.Text += ", " + Convert.ToString(item["WorkState"]);
                lblOfficeDetails.Text += "&nbsp;&nbsp;" + Convert.ToString(item["WorkZip"]);

                Control ph = e.Item.FindControl("mainPlaceHolder");
                foreach (Control ctrl in ph.Controls)
                {
                    if (ctrl.GetType() != typeof(LiteralControl))
                        continue;

                    LiteralControl lit = (LiteralControl)ctrl;
                    lit.Text = lit.Text.Replace("@index@", e.Item.ItemIndex.ToString());
                }
            }
        }
        #endregion
    }
}
